Period picker
Allow users to select a range of dates quickly and intuitively.
#Examples
Default: Button shows selected range with presets available. Always has a default presets with the most commonly used date range.
Period picker consists of two main elements:
- Button (with clock icon) using two lines:
- Line 1: Active preset or custom date range.
- Line 2: Start and end dates of selected range
- Popover (triggered by button click) with:
- Preset tabs (e.g., "Last 7 Days," "Last Month")
- Interactive calendar view for custom range selection
const [period, setPeriod] = React.useState<PeriodPickerValue | null>({
start: new Date(2023, 4, 1),
end: new Date(2023, 4, 31),
type: PeriodType.Custom,
});
return <PeriodPicker aria-label="Select period" value={period} onChange={setPeriod} />;
#Usage with hidden presets
Used when preset data is unavailable, focusing on custom selection.
const [period, setPeriod] = React.useState<PeriodPickerValue | null>({
start: new Date(2023, 4, 1),
end: new Date(2023, 4, 31),
type: PeriodType.Custom,
});
return (
<PeriodPicker
aria-label="Select period"
value={period}
onChange={setPeriod}
hiddenPresets={[
PeriodType.LastSevenDays,
PeriodType.LastFourteenDays,
PeriodType.LastThirtyDays,
PeriodType.Last365Days,
]}
/>
);
#Usage with condensed variant
Button (with clock icon) displaying selected range in one line.
const [period, setPeriod] = React.useState<PeriodPickerValue | null>({
start: new Date(2023, 4, 1),
end: new Date(2023, 4, 31),
type: PeriodType.Custom,
});
return <PeriodPicker aria-label="Select period" value={period} onChange={setPeriod} condensed />;
#Usage with time zone conversion
When the dates are provided in UTC format (e.g. when dates from the server are not localized) make sure to convert it from UTC to local when passed to the value
prop and from local to UTC when updating the period
state from within the onChange
callback.
const [period, setPeriod] = React.useState<PeriodPickerValue | null>({
start: new Date(2023, 4, 1),
end: new Date(2023, 4, 31),
type: PeriodType.Custom,
});
function localToUtc(date: Date): Date {
return new Date(
Date.UTC(
date.getFullYear(),
date.getMonth(),
date.getDate(),
date.getHours(),
date.getMinutes(),
date.getSeconds()
)
);
}
function utcToLocal(date: Date): Date {
return new Date(
date.getUTCFullYear(),
date.getUTCMonth(),
date.getUTCDate(),
date.getUTCHours(),
date.getUTCMinutes(),
date.getUTCSeconds()
);
}
return (
<PeriodPicker
aria-label="Select period"
value={
period
? {
start: utcToLocal(period.start),
end: utcToLocal(period.end),
type: period.type,
}
: null
}
onChange={(period) => {
setPeriod(
period
? {
start: localToUtc(period.start),
end: localToUtc(period.end),
type: period.type,
}
: null
);
}}
/>
);
#Usage with UTC offset
When a UTC offset is provided, all preset calculations (such as "Last 5 minutes", "Yesterday", etc.) are based on the current time adjusted by that offset. This means "now" reflects the time at the specified UTC offset, not the system or browser time.
const utcOffset = -10 * 60; // Example UTC offset in minutes (-10 hours)
const now = new Date();
now.setMinutes(now.getMinutes() + utcOffset); // Adjust current time by UTC offset
const start = new Date(now.getTime() - 5 * 60 * 1000); // 5 minutes ago
const end = new Date(now);
const [period, setPeriod] = React.useState<PeriodPickerValue | null>({
start,
end,
type: PeriodType.Now,
});
return (
<Content flexDirection="row" padding="none" gap="large">
<PeriodPicker
aria-label="Select period"
value={period}
onChange={setPeriod}
options={{ utcOffset }}
/>
{period && (
<div>
<div>
<InlineText>{`Start: ${period.start.toISOString()}`}</InlineText>
</div>
<div>
<InlineText>{`End: ${period.end.toISOString()}`}</InlineText>
</div>
</div>
)}
</Content>
);
#Usage with includeToday option
When includeToday: false
is set, the "This Month", "This Quarter", and "This Year" presets will end at yesterday instead of today. By default, includeToday
is true
.
const [period, setPeriod] = React.useState<PeriodPickerValue | null>({
start: new Date(2023, 4, 1),
end: new Date(2023, 4, 31),
type: PeriodType.Custom,
});
return (
<Content flexDirection="row" padding="none" gap="large">
<PeriodPicker
aria-label="Select period with includeToday option"
value={period}
onChange={setPeriod}
options={{ includeToday: false }}
/>
{period && (
<div>
<div>
<InlineText>{`Start: ${period.start.toISOString()}`}</InlineText>
</div>
<div>
<InlineText>{`End: ${period.end.toISOString()}`}</InlineText>
</div>
</div>
)}
</Content>
);
#Usage with week start
When a week start is provided, the calendar view will start the week on the specified day. This is useful when the user's locale or system week start day is different from the default (Sunday).
const [period, setPeriod] = React.useState<PeriodPickerValue | null>({
start: new Date(2023, 4, 1),
end: new Date(2023, 4, 31),
type: PeriodType.Custom,
});
return (
<Content flexDirection="row" padding="none" gap="large">
<PeriodPicker
aria-label="Select period with week starting Monday"
value={period}
onChange={setPeriod}
options={{ weekStart: 1 }} // 0 = Sunday, 1 = Monday, 2 = Tuesday, etc.
/>
{period && (
<div>
<div>
<InlineText>{`Start: ${period.start.toISOString()}`}</InlineText>
</div>
<div>
<InlineText>{`End: ${period.end.toISOString()}`}</InlineText>
</div>
</div>
)}
</Content>
);
#Properties
Property | Description | Defined | Value |
---|---|---|---|
valueRequired | | object The value of the component | ||
onChangeRequired | function Callback that is called when the value changes | ||
optionsOptional | object Options for period calculations | ||
minDateOptional | date | ||
maxDateOptional | date | ||
literal-union[] | |||
condensedOptional | boolean | ||
disabledOptional | boolean Whether the component is disabled | ||
aria-labelOptional | string Label of the form control | ||
aria-describedbyOptional | string ID of an an element that describes what the form control is for | ||
aria-labelledbyOptional | string ID of an an element that labels this form control | ||
periodButtonVariantOptional | "borderless" | "ctaDefault" | "ctaPrimary" | "ctaSecondary" | "default" | "destructive" | "primary" | "secondary" How should the button look | ||
periodButtonSizeOptional | "large" | "medium" | "small" Controls the size of the button - defaults to medium | ||
periodButtonStyleOptional | object Add inline style for the button only if necessary | ||
strategyOptional | "absolute" | "fixed" Position popover using fixed or absolute | ||
data-observe-keyOptional | string Unique string, used by external script e.g. for event tracking | ||
classNameOptional | string Custom className that's applied to the outermost element (only intended for special cases) | ||
styleOptional | object Style object to apply custom inline styles (only intended for special cases) | ||
tabIndexOptional | number Tab index of the outermost HTML element of the component | ||
onKeyDownOptional | function Callback for onKeyDown event | ||
onMouseDownOptional | function Callback for onMouseDown event | ||
onMouseEnterOptional | function Callback for onMouseEnter event | ||
onMouseLeaveOptional | function Callback for onMouseLeave event | ||
onFocusOptional | function Callback for onFocus event | ||
onBlurOptional | function Callback for onBlur event |
#Guidelines
#Best practices
#Do not use when
#Accessibility
Explore detailed guidelines for this component: Accessibility Specifications